【SQL】サブクエリ(副問い合わせ)を3分でわかりやすく解説 您所在的位置:网站首页 sql 用途 【SQL】サブクエリ(副問い合わせ)を3分でわかりやすく解説

【SQL】サブクエリ(副問い合わせ)を3分でわかりやすく解説

2024-07-13 09:46| 来源: 网络整理| 查看: 265

SQLのサブクエリ(副問い合わせ)とは「SQL文中にまた別のSQLを入れ子にして記述すること」です。

例えば、以下のようなSQLがサブクエリの一例です。(SELECT文の中に別のSELECT文が記述されています。)

SELECT * FROM (SELECT ID FROM PointList) AS Sub;

サブクエリを利用できるようになると、単純にSELECT文を記述するだけではできない複雑なレコード抽出を行うことが可能になります。

このページではSQL初心者向けにサブクエリ(副問い合わせ)の使い方を1からわかりやすくサンプルコード付きで3分で解説。自分ひとりでサブクエリを使ったSQL文を記述できるようにご説明します。

このページで学べる内容 サブクエリ(副問い合わせ)とは?サブクエリの構文ルールサブクエリ(副問い合わせ)の利用方法

データベースエンジニアを目指す方であれば知らないと恥ずかしい超・基本知識です。是非最後までご覧ください。

SQL文の基本ルール(大文字/小文字の区別、コメントの付与など)を始めに学んでおきたい方は以下の記事を先にご覧ください。

【SQL】基本的な記述ルール5つを1分で解説【SQL入門】SQL文を記述する際の基本ルール4つを解説します。OK例/NG例のそれぞれをサンプルコード付きでわかりやすく説明しています。たった今SQL文でエラーが発生して「ハマってる」人は必見です。it-biz.online2023.10.04 スポンサーリンク サブクエリ(副問い合わせ)をわかりやすくサブクエリ構文ルールサブクエリの利用方法システムエンジニアを目指したい方はサブクエリ(副問い合わせ)をわかりやすく 図1:サブクエリのイメージ

サブクエリとは、SQLの中に記述する別のSQL。言い換えると一時的なビューのようなものです。

例えば以下のSQL文はSELECT文の中にSELECT文が記述されているため、サブクエリの一例です。

SELECT * FROM (SELECT ID FROM PointList) AS Sub;

と、説明してもこれだけではいまいち理解できないかと思いますので、具体例を見ながら1個1個わかりやすく説明していきます。

まずは、以下のようなテーブルを用意します。

サブクエリ,副問い合わせ,わかりやすくサンプルテーブル「PointList」

参考までに上記のPointListテーブルを用意するためのCREATE TABLE文/INSERT文を掲載しておきます。

-- PointList定義 CREATE TABLE PointList ( ID INT(3) NOT NULL PRIMARY KEY, Name VARCHAR(50) NOT NULL, Class VARCHAR(1), Japanese INT(3) DEFAULT '0', Math INT(3) DEFAULT '0', English INT(3) DEFAULT '0' ); /*PointList定義 +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | ID | int(3) | NO | PRI | NULL | | | Name | varchar(50) | NO | | NULL | | | Class | varchar(1) | YES | | NULL | | | Japanese | int(3) | YES | | 0 | | | Math | int(3) | YES | | 0 | | | English | int(3) | YES | | 0 | | +----------+-------------+------+-----+---------+-------+ */ -- PointListへレコード登録 INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (1,'佐藤','A',100,100,85); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (2,'鈴木','A',90,70,70); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (3,'高橋','A',85,70,65); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (4,'中村','A',90,65,85); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (5,'小林','B',70,90,65); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (6,'山口','B',90,85,85); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (7,'田中','B',70,90,65); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (8,'伊藤','B',70,90,NULL); -- 結果確認 SELECT * FROM PointList; /* +----+------+-------+----------+------+---------+ | ID | Name | Class | Japanese | Math | English | +----+------+-------+----------+------+---------+ | 1 | 佐藤 | A | 100 | 100 | 85 | | 2 | 鈴木 | A | 90 | 70 | 70 | | 3 | 高橋 | A | 85 | 70 | 65 | | 4 | 中村 | A | 90 | 65 | 85 | | 5 | 小林 | B | 70 | 90 | 65 | | 6 | 山口 | B | 90 | 85 | 85 | | 7 | 田中 | B | 70 | 90 | 65 | | 8 | 伊藤 | B | 70 | 90 | NULL | +----+------+-------+----------+------+---------+ */ -- PointList定義 CREATE TABLE PointList ( ID INT(3) NOT NULL PRIMARY KEY, Name VARCHAR(50) NOT NULL, Class VARCHAR(1), Japanese INT(3) DEFAULT '0', Math INT(3) DEFAULT '0', English INT(3) DEFAULT '0' ); /*PointList定義 +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | ID | int(3) | NO | PRI | NULL | | | Name | varchar(50) | NO | | NULL | | | Class | varchar(1) | YES | | NULL | | | Japanese | int(3) | YES | | 0 | | | Math | int(3) | YES | | 0 | | | English | int(3) | YES | | 0 | | +----------+-------------+------+-----+---------+-------+ */ -- PointListへレコード登録 INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (1,'佐藤','A',100,100,85); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (2,'鈴木','A',90,70,70); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (3,'高橋','A',85,70,65); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (4,'中村','A',90,65,85); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (5,'小林','B',70,90,65); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (6,'山口','B',90,85,85); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (7,'田中','B',70,90,65); INSERT INTO PointList (ID,Name,Class,Japanese,Math,English) VALUES (8,'伊藤','B',70,90,NULL); -- 結果確認 SELECT * FROM PointList; /* +----+------+-------+----------+------+---------+ | ID | Name | Class | Japanese | Math | English | +----+------+-------+----------+------+---------+ | 1 | 佐藤 | A | 100 | 100 | 85 | | 2 | 鈴木 | A | 90 | 70 | 70 | | 3 | 高橋 | A | 85 | 70 | 65 | | 4 | 中村 | A | 90 | 65 | 85 | | 5 | 小林 | B | 70 | 90 | 65 | | 6 | 山口 | B | 90 | 85 | 85 | | 7 | 田中 | B | 70 | 90 | 65 | | 8 | 伊藤 | B | 70 | 90 | NULL | +----+------+-------+----------+------+---------+ */

サブクエリ(副問い合わせ)を理解できるように、まずはこのテーブルからClassごとの平均点を取得するようなビューを定義する場合を考えます。

CREATE VIEW文とAVG関数を活用して以下のようなビューを作成します。

CREATE VIEW AVG_PointList  AS SELECT Class, AVG(Japanese), AVG(Math), AVG(English) FROM PointList GROUP BY Class; -- ビューの確認 SELECT * FROM AVG_PointList; /* +-------+---------------+-----------+--------------+ | Class | AVG(Japanese) | AVG(Math) | AVG(English) | +-------+---------------+-----------+--------------+ | A | 91.2500 | 76.2500 | 76.2500 | | B | 75.0000 | 88.7500 | 71.6667 | +-------+---------------+-----------+--------------+ */

参考:CREATE VIEW文 / AVG関数

クラス A / B それぞれの平均点の一覧が分かるビューが完成です。

さらにこのとき、Class「A」だけの平均点を知りたいような場合を考えてみます。

出来上がるのが以下のSQLです。

-- Class[A]のみの平均点を取得 SELECT * FROM AVG_PointList WHERE Class = 'A'; /* 結果 +-------+---------------+-----------+--------------+ | Class | AVG(Japanese) | AVG(Math) | AVG(English) | +-------+---------------+-----------+--------------+ | A | 91.2500 | 76.2500 | 76.2500 | +-------+---------------+-----------+--------------+ */

先ほど定義したビュー「AVG_PointList」のClass列が「A」となるレコードをWHERE句で指定するSELECT文です。

実は、今回解説するサブクエリ(副問い合わせ)を使うことでここまで見てきたビュー定義とビューからのレコード抽出を1つのSELECT文で実行することができます。

早速、上記と同じレコード抽出文をサブクエリを使って記述した結果がこちら。

SELECT * FROM (SELECT Class, AVG(Japanese), AVG(Math), AVG(English) FROM PointList GROUP BY Class) AS Sub WHERE Class = 'A'; /* 結果→先ほどと同じ結果が取得できる +-------+---------------+-----------+--------------+ | Class | AVG(Japanese) | AVG(Math) | AVG(English) | +-------+---------------+-----------+--------------+ | A | 91.2500 | 76.2500 | 76.2500 | +-------+---------------+-----------+--------------+

いかがでしょうか。先ほどと同じような結果を取得することができました。

なぜこんなことが可能になるのでしょう。先ほどのビューに対して発行したSQLと見比べてみるとその理由が一目瞭然です。

サブクエリ 難しいサブクエリは一時的な使い捨てのビュー

簡単に説明するとサブクエリとは一時的な使い捨てのビューのようなもの。ビュー定義のSELECT文をそのまま別のSELECT文に入れてしまったのがサブクエリ(副問い合わせ)の正体です。

決して考え方は難しくはありません。

先ほどは、テーブルからビュー「AVG_PointList」を定義し、そのビューに対してSELECT文を発行していましたが、サブクエリを利用すれば、一時的に使い捨てのビュー(Sub)を作成し、同時にそのビューに対してSELECT文を発行することができるということ。

もう1度、サブクエリを利用したSQLとそうでないSQLを見比べてみましょう。

-- ①ビューに対するSQL SELECT * FROM AVG_PointList WHERE Class = 'A'; -- ②サブクエリを利用したSQL SELECT * FROM (SELECT Class, AVG(Japanese), AVG(Math), AVG(English) FROM PointList GROUP BY Class) AS Sub WHERE Class = 'A'; /* 結果→先ほど同じ結果が取得できる +-------+---------------+-----------+--------------+ | Class | AVG(Japanese) | AVG(Math) | AVG(English) | +-------+---------------+-----------+--------------+ | A | 91.2500 | 76.2500 | 76.2500 | +-------+---------------+-----------+--------------+ サブクエリ構文ルール

サブクエリの構文ルールは簡単です。( )で閉じて直後にAS句でサブクエリ名称を指定するだけ。

~~~(SELECT句)AS サブクエリ名称~~~ SELECT * FROM (SELECT A, B, C FROM Sample) AS Sub;

サブクエリの名称に特に決まりはありませんが、サブクエリはあくまでも一時的に利用するだけの使い捨てなので「Sub」と指定することが多いです。

SELECT * FROM (SELECT Class, AVG(Japanese), AVG(Math), AVG(English) FROM PointList GROUP BY Class) -- サブクエリの名称はなんでもOK AS TestName WHERE Class = 'A' ポイントサブクエリは一時的な使い捨てのビューのようなものサブクエリ,副問い合わせサブクエリの利用方法

サブクエリの基本をより具体例にイメージできるようにもう1つだけ具体例を提示して解説を終えたいと思います。

今回はPointListテーブルに加えて「ClassMember」テーブルを用意します。

サブクエリ,副問い合わせサンプルテーブル②

テーブル定義:参考(CREATE TABLE)

-- ClassMember定義 CREATE TABLE ClassMember ( ID INT(3) NOT NULL PRIMARY KEY, Name VARCHAR(50) NOT NULL, Class VARCHAR(1), Gender VARCHAR(1), Address VARCHAR(4) ); /* ClassMember定義 +---------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+-------+ | ID | int(3) | NO | PRI | NULL | | | Name | varchar(50) | NO | | NULL | | | Class | varchar(1) | YES | | NULL | | | Gender | varchar(1) | YES | | NULL | | | Address | varchar(4) | YES | | NULL | | +---------+-------------+------+-----+---------+-------+ */

利用するダミーレコード:参考(INSERT文)

-- ClassMemberへレコード登録 INSERT INTO ClassMember (ID,Name,Class,Gender,Address) VALUES (1,'佐藤','A','男','東京都'); INSERT INTO ClassMember (ID,Name,Class,Gender,Address) VALUES (2,'鈴木','A','女','東京都'); INSERT INTO ClassMember (ID,Name,Class,Gender,Address) VALUES (3,'高橋','A','男','東京都'); INSERT INTO ClassMember (ID,Name,Class,Gender,Address) VALUES (4,'中村','A','女','埼玉県'); INSERT INTO ClassMember (ID,Name,Class,Gender,Address) VALUES (5,'小林','B','男','埼玉県'); INSERT INTO ClassMember (ID,Name,Class,Gender,Address) VALUES (6,'山口','B','女','埼玉県'); INSERT INTO ClassMember (ID,Name,Class,Gender,Address) VALUES (7,'田中','B','男','神奈川県'); INSERT INTO ClassMember (ID,Name,Class,Gender,Address) VALUES (8,'伊藤','B','女','神奈川県'); -- 結果確認 SELECT * FROM ClassMember; /* +----+------+-------+--------+----------+ | ID | Name | Class | Gender | Address | +----+------+-------+--------+----------+ | 1 | 佐藤 | A | 男 | 東京都 | | 2 | 鈴木 | A | 女 | 東京都 | | 3 | 高橋 | A | 男 | 東京都 | | 4 | 中村 | A | 女 | 埼玉県 | | 5 | 小林 | B | 男 | 埼玉県 | | 6 | 山口 | B | 女 | 埼玉県 | | 7 | 田中 | B | 男 | 神奈川県 | | 8 | 伊藤 | B | 女 | 神奈川県 | +----+------+-------+--------+----------+ */

サブクエリを利用して、2つのテーブルをもとに「東京都」出身の生徒の成績を出力してみたいと思います。

出来上がるSQL文がこちら。

-- SELECT * FROM (SELECT PointList.* ,ClassMember.Address FROM PointList LEFT OUTER JOIN ClassMember ON PointList.ID = ClassMember.ID) AS Sub WHERE Address = '東京都'; /* 結果 +----+------+-------+----------+------+---------+---------+ | ID | Name | Class | Japanese | Math | English | Address | +----+------+-------+----------+------+---------+---------+ | 1 | 佐藤 | A | 100 | 100 | 85 | 東京都 | | 2 | 鈴木 | A | 90 | 70 | 70 | 東京都 | | 3 | 高橋 | A | 85 | 70 | 65 | 東京都 | +----+------+-------+----------+------+---------+---------+ */

今回もサブクエリをFROM句で利用しています。

このFROM句に記載されたSELECT文は、PointListテーブルとClassMemberテーブルを外部結合した結果を返します。

したがって、以下のようなビューが一時的に定義され、そこから「Address = 東京都」となるレコードを引っ張ってきているということです。

CREATE VIEW SampleView AS SELECT PointList.* ,ClassMember.Address FROM PointList LEFT OUTER JOIN ClassMember ON PointList.ID = ClassMember.ID; SELECT * FROM SampleView; /* +----+------+-------+----------+------+---------+----------+ | ID | Name | Class | Japanese | Math | English | Address | +----+------+-------+----------+------+---------+----------+ | 1 | 佐藤 | A | 100 | 100 | 85 | 東京都 |←先ほどのSQLはここだけ取得 | 2 | 鈴木 | A | 90 | 70 | 70 | 東京都 |←先ほどのSQLはここだけ取得 | 3 | 高橋 | A | 85 | 70 | 65 | 東京都 |←先ほどのSQLはここだけ取得 | 4 | 中村 | A | 90 | 65 | 85 | 埼玉県 | | 5 | 小林 | B | 70 | 90 | 65 | 埼玉県 | | 6 | 山口 | B | 90 | 85 | 85 | 埼玉県 | | 7 | 田中 | B | 70 | 90 | 65 | 神奈川県 | | 8 | 伊藤 | B | 70 | 90 | NULL | 神奈川県 | +----+------+-------+----------+------+---------+----------+ */ サブクエリ(副問い合わせ)のまとめサブクエリはSQL文中に記載された別のSQL文のことサブクエリは一時的に使い捨てされるビューのようなものなので必ず仮の名称を指定する必要があるサブクエリの応用編

サブクエリ(副問い合わせ)を細かく分類していくと、「スカラ・サブクエリ」や「相関サブクエリ」なるサブクエリも存在します。

スカラ・サブクエリ→結果が1行1列となるサブクエリ相関サブクエリ→外側のSQLと「相関」して処理を実施するサブクエリ

詳しくは以下のページで解説をしておりますので、この機会に合わせて学習しておきましょう!

【SQL】スカラ・サブクエリを1分でわかりやすく解説【初心者向け】スカラ・サブクエリ(Scala Subquery)とは何か?処理の内容や使い方・注意点を図解付き・サンプルコード付きでわかりやすく解説します。it-biz.online2022.10.02 【SQL】相関サブクエリ(相関副問い合わせ)とは?3分でわかりやすく解説【初心者向け】相関サブクエリの使い方・処理内容を1からわかりやすく図解付き・サンプルコード付きで解説します。it-biz.online2022.10.03システムエンジニアを目指したい方は

システムエンジニアを目指す方や、IT知識を1から身につけたい方は以下のページをご覧ください。

正直どこから学び始めればよいかわからない。どのように勉強していけば、エンジニアとしてのスキルが磨けるか?が分からない・・・という方は必見です。

システムエンジニア向けに「できるエンジニア」になる方法を1から解説しておりますので、是非ご覧ください。

1人前のシステムエンジニア(SE)になるために勉強した5つのこと本ページでは、1人前のシステムエンジニアになるために学んだこと・読んだ本・勉強したプログラミング言語を現役のエンジニアが1から紹介しています。「正直何を勉強したらよいかわからない」という疑問をお持ちの方は特に必見です。it-biz.online2021.07.29


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有